//-----------------------------------------------------------------------
// <copyright file="MLObjectBrowser.cs" company="MAPILab Ltd">
//     Copyright (c) MAPILab Ltd.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace MAPILab.SharePoint.Explorer.ObjectBrowser
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Reflection;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    using MAPILab.SharePoint.Explorer.CodeForm;
    using MAPILab.SharePoint.Explorer.Docking;
    using MAPILab.SharePoint.Explorer.Information;
    using MAPILab.SharePoint.Explorer.ObjectBrowser.AsyncWork;
    using MAPILab.SharePoint.Explorer.ObjectBrowser.TreeExpand;
    using MAPILab.SharePoint.Explorer.Utilities;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Administration;
    using Microsoft.SharePoint.Upgrade;

    /// <summary>
    /// Object browser, show object tree, propery window, etc. 
    /// </summary>
    public partial class MLObjectBrowser : DockContent
    {
        #region Fields

        /// <summary>
        /// Is Ctrl Key Pressed
        /// </summary>
        private bool CtrlPress = false;

        /// <summary>
        /// Root objects
        /// </summary>
        private object[] browsedObjects;              
        
        /// <summary>
        /// Run in async mode or not
        /// </summary>
        public static bool isAsync = Properties.Settings.Default.UseAsyncMethod;

        /// <summary>
        /// Three collection for sync method
        /// </summary>
        private List<MLNodeInfo> treeNodeCollection;

        /// <summary>
        /// AsyncWorker for this form
        /// </summary>
        private MLAsyncWorker asyncWorker;

        /// <summary>
        /// Parent form
        /// </summary>
        private MLMainForm mainForm;

        /// <summary>
        /// Code form
        /// </summary>
        private DockContent previousForm;

        /// <summary>
        /// tree is expending
        /// </summary>
        private bool isRunning = false;

        #endregion

        #region Properties

        /// <summary>
        /// Parent form
        /// </summary>
        public MLMainForm MainForm
        {
            get { return mainForm; }
            set { mainForm = value; }
        }

        /// <summary>
        /// AsyncWorker for this form
        /// </summary>
        public MLAsyncWorker AsyncWorker
        {
            get { return asyncWorker; }
        }

        /// <summary>
        /// Gets and sets root objects
        /// </summary>
        public object[] BrowsedObjects
        {
            get { return browsedObjects; }
            set { browsedObjects = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsRunning
        {
            get { return isRunning; }
            set { isRunning = value; }
        }

        /// <summary>
        /// Form that opens this form
        /// </summary>
        public DockContent PreviousForm
        {
            get { return previousForm; }
            set { previousForm = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default Constructor
        /// </summary>
        public MLObjectBrowser()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        /// <summary>
        /// Main form load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            OnLoad();
        }

        /// <summary>
        /// On form refresh
        /// </summary>
        public override void Refresh()
        {
            //base.Refresh();

            OnLoad();
        }

        /// <summary>
        /// On this form text changed 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ObjectBrowser_TextChanged(object sender, EventArgs e)
        {
            if (this.Text == String.Empty || this.Text == null)
            {
                this.Text = "Browser Window";
            }
        }

        /// <summary>
        /// On tree node select
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            GetPropertyGrid(e.Node.Tag as MLTreeTag);
        }

        /// <summary>
        /// On copy click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void copyToClipboard_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null)
            {
                Clipboard.SetText(hti.Node.Text);
                return;
            }

            if (generalPropsGrid.Bounds.Contains(generalPropsGrid.PointToClient(hitPoint)))
            {
                if (generalPropsGrid.SelectedGridItem != null)
                    Clipboard.SetText(generalPropsGrid.SelectedGridItem.Label);
                return;
            }

            if (typeInfoPropsGrid.Bounds.Contains(typeInfoPropsGrid.PointToClient(hitPoint)))
            {
                if (typeInfoPropsGrid.SelectedGridItem != null)
                    Clipboard.SetText(typeInfoPropsGrid.SelectedGridItem.Label);
                return;
            }
        }

        /// <summary>
        /// On open in new window click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openInNewWindow_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                MLTreeTag tag = hti.Node.Tag as MLTreeTag;

                if (tag.ObjInstance != null)
                {
                    MLObjectBrowser newWindow = new MLObjectBrowser();
                    newWindow.BrowsedObjects = new object[] { tag.ObjInstance };
                    newWindow.Text = hti.Node.FullPath;

                    if (mainForm.dockPanel.DocumentStyle == MAPILab.SharePoint.Explorer.Docking.DocumentStyle.SystemMdi)
                    {
                        newWindow.MdiParent = MdiParent;
                        newWindow.Show();
                    }
                    else
                    {
                        newWindow.Show(mainForm.dockPanel);
                    }
                }
            }
        }

        /// <summary>
        /// On delete persisted object click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deletePersistedObject_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                MLTreeTag tag = hti.Node.Tag as MLTreeTag;

                if (MessageBox.Show("Do you want to delete persisted object " + tag.ObjInstance.ToString() + "?",
                                    "Deleting persisted object", 
                                    MessageBoxButtons.YesNo, 
                                    MessageBoxIcon.Warning, 
                                    MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                {
                    if (tag.ObjInstance != null)
                    {
                        try
                        {
                            if (tag.ObjInstance is SPPersistedObject)
                            {
                                SPPersistedObject po = tag.ObjInstance as SPPersistedObject;
                                po.Delete();
                            }
                            else if (tag.ObjInstance is MLInvalidPersistedObject)
                            {
                                MLInvalidPersistedObject ipo = tag.ObjInstance as MLInvalidPersistedObject;
                                ipo.Delete();
                            }
                            else
                            {
                                return;
                            }

                            hti.Node.Remove();
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, Properties.Resources.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// On context menu opening
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                MLTreeTag tag = hti.Node.Tag as MLTreeTag;

                deletePersistedObjectToolStripMenuItem.Visible = false;
                addToStoredToolStripMenuItem.Visible = false;
                openInInternetExplorerToolStripMenuItem.Visible = false;
                updateToolStripMenuItem.Visible = false;
                if (tag.ObjInstance != null)
                {
                    if (tag.ObjInstance is SPPersistedObject || tag.ObjInstance is MLInvalidPersistedObject)
                        deletePersistedObjectToolStripMenuItem.Visible = true;
                    if (tag.ObjInstance is SPFarm || tag.ObjInstance is SPManager || tag.ObjInstance is SPTimerService ||
                        tag.ObjInstance is SPWebApplication || tag.ObjInstance is SPSite || tag.ObjInstance is SPWeb || tag.ObjInstance is SPPersistedObject)
                        addToStoredToolStripMenuItem.Visible = true;
                    if (tag.ObjInstance is SPWeb || tag.ObjInstance is SPSite)
                        openInInternetExplorerToolStripMenuItem.Visible = true;

                    MethodInfo methodUpdate = tag.ObjInstance.GetType().GetMethod("Update", new Type[] { });
                    MethodInfo methodUpdateParent = tag.ObjInstance.GetType().GetMethod("UpdateParent", new Type[] { });
                    if (methodUpdate != null || methodUpdateParent != null)
                        updateToolStripMenuItem.Visible = true;
                }

                openInNewWindowToolStripMenuItem.Visible = true;
            }
            else
            {
                openInNewWindowToolStripMenuItem.Visible = false;
                deletePersistedObjectToolStripMenuItem.Visible = false;
            }
        }

        /// <summary>
        /// Show Help
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="hlpevent"></param>
        private void ObjectForm_HelpRequested(object sender, HelpEventArgs hlpevent)
        {
            MLHtmlHelper.ShowTopic(this, "explorer", 111);
        }

        /// <summary>
        /// On form closing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ObjectBrowser_FormClosing(object sender, FormClosingEventArgs e)
        {
            /*
            for (int i = 0; i < browsedObjects.Length; i++)
            {
                if (browsedObjects[i] is IDisposable)
                {
                    (browsedObjects[i] as IDisposable).Dispose();
                }
            }

            for (int i = 0; i < treeNodeCollection.Count; i++)
            {
                MLTreeTag treeTag = treeNodeCollection[i].Node.Tag as MLTreeTag;

                if (treeTag != null && treeTag.ObjInstance is IDisposable)
                {
                    (treeTag.ObjInstance as IDisposable).Dispose();
                }
            }
            */

            if (previousForm != null &&
                previousForm is MLCodeForm)
            {
                (previousForm as MLCodeForm).ResultObjectBrowser = null;
            }

            mainForm = null;
            browsedObjects = null;
            treeNodeCollection = null;

            if (asyncWorker!=null)    
                asyncWorker.Dispose();
            
            this.Dispose();
        }

        /// <summary>
        /// Before object tree expand
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectTree_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            bool IsAdded = false;
            
            if (Properties.Settings.Default.UseAsyncMethod && !CtrlPress)
            {
                mainForm.Abort.Enabled = true;
                mainForm.abortToolStripMenuItem.Enabled = true;

                if (asyncWorker == null)
                {
                    asyncWorker = new MLAsyncWorker(this);
                }

                IsAdded = asyncWorker.AddWork(new MLDoWork(WorkState.expand, e.Node, null, 0));
            }

            //Build tree in sync mode
            if (e.Node != null && e.Node.Tag != null && !IsAdded)
            {
                MLTreeTag treeTag = e.Node.Tag as MLTreeTag;
                if (!(treeTag != null && treeTag.Syntetic))
                {
                    MLObjectTreeExpand objectTreeExpand = new MLObjectTreeExpand();

                    if (treeTag != null && treeTag.PersistedObjectRole)
                    {
                        treeNodeCollection = objectTreeExpand.UpdatePersistedChildObjects(treeTag.ObjInstance, e.Node);
                    }
                    else
                    {
                        treeNodeCollection = objectTreeExpand.UpdateNodeMembers(treeTag.ObjInstance, e.Node.Nodes);
                    }

                    //Rendering
                    WorkExpandEnd(e.Node);
                }
            }
        }

        /// <summary>
        /// After object tree collapse
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectTree_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Nodes.Count > 0 && e.Node.Tag != null && (e.Node.Tag is MLTreeTag))
            {
                if (!(e.Node.Tag as MLTreeTag).Syntetic)
                {
                    e.Node.Nodes.Clear();
                    e.Node.Nodes.Add("Loading...");
                }
                else
                {
                    foreach (TreeNode node in e.Node.Nodes)
                    {
                        node.Collapse();
                        node.Checked = false;
                    }
                }
            }
        }

        /// <summary>
        /// Add current object to stored
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToStoredToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                object o = (hti.Node.Tag as MLTreeTag).ObjInstance;
                if (o == null)
                    return;

                string filename = String.Empty;

                CodeLanguage codelanguage = CodeLanguage.CSharp;
                if (Properties.Settings.Default.CodeLanguage == "VBNet")
                {
                    codelanguage = CodeLanguage.VBNet;
                }

                MLUtils.CreateScript(o, codelanguage);
            }
        }

        /// <summary>
        /// Open object with Url property in Internet Explorer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openInInternetExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                object o = (hti.Node.Tag as MLTreeTag).ObjInstance;
                if (o == null)
                    return;

                string Url = String.Empty;

                if (o is SPSite)
                {
                    SPSite site = o as SPSite;
                    Url = site.Url;    
                }
                if (o is SPWeb)
                {
                    SPWeb web = o as SPWeb;
                    Url = web.Url;
                }

                Process.Start(Url);                    
            }
        }

        /// <summary>
        /// Make sync mode on Ctrl is down
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectTree_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control)
            {
                CtrlPress = true;
            }
        }

        /// <summary>
        /// Resume Async mode on Ctrl is up
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void objectTree_KeyUp(object sender, KeyEventArgs e)
        {
            CtrlPress = false;
        }

        /// <summary>
        /// Update object
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void updateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Point hitPoint = contextMenuStrip.Bounds.Location;

            TreeViewHitTestInfo hti = objectTree.HitTest(objectTree.PointToClient(hitPoint));
            if (hti.Node != null && hti.Node.Tag != null && hti.Node.Tag is MLTreeTag)
            {
                object o = (hti.Node.Tag as MLTreeTag).ObjInstance;
                if (o == null)
                    return;

                try
                {
                    MethodInfo methodUpdate = o.GetType().GetMethod("Update", new Type[] { });

                    if (methodUpdate != null)
                    {
                        methodUpdate.Invoke(o, null);
                    }
                    else
                    {
                        MethodInfo methodUpdateParent = o.GetType().GetMethod("UpdateParent", new Type[] { });
                        if (methodUpdateParent != null)
                        {
                            methodUpdateParent.Invoke(o, null);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MLObjectBrowser newWindow = new MLObjectBrowser();
                    newWindow.BrowsedObjects = new object[] { ex };
                    newWindow.Text = hti.Node.FullPath;

                    if (mainForm.dockPanel.DocumentStyle == MAPILab.SharePoint.Explorer.Docking.DocumentStyle.SystemMdi)
                    {
                        newWindow.MdiParent = MdiParent;
                        newWindow.Show();
                    }
                    else
                    {
                        newWindow.Show(mainForm.dockPanel);
                    }
                }
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// On form load
        /// </summary>
        private void OnLoad()
        {
            treeNodeCollection = new List<MLNodeInfo>();

            objectTree.Nodes.Clear();

            //Display style
            if (IsMdiChild)
            {
                mainForm = this.ParentForm as MLMainForm;
            }
            //else
            //{
            //    mainForm = this.MdiParent as MLMainForm;
            //}

            //Choose sync or async method of tree building
            if (Properties.Settings.Default.UseAsyncMethod)
            {
                asyncWorker = new MLAsyncWorker(this);
                asyncWorker.AddWork(new MLDoWork(WorkState.start, null, null, 0));
            }
            else
            {
                StartRootSync();
            }
        }

        /// <summary>
        /// Gets checked objects
        /// </summary>
        /// <returns>Checked objects (name, object)</returns>
        public Dictionary<string, object> GetCheckedObjects()
        {
            Dictionary<string, object> checkObjects = new Dictionary<string, object>();
            ScanForCheckedObjects(objectTree.Nodes, checkObjects, false);
            return checkObjects;
        }

        /// <summary>
        /// Uncheck checked objects
        /// </summary>
        public void UncheckAll()
        {
            ScanForCheckedObjects(objectTree.Nodes, null, true);
        }

        /// <summary>
        /// Scan all checked nodes
        /// </summary>
        /// <param name="nodes">nodes to scan</param>
        /// <param name="checkObjects">objects to return</param>
        /// <param name="justUncheck">if need to uncheck</param>
        private void ScanForCheckedObjects(TreeNodeCollection nodes, Dictionary<string, object> checkObjects, bool justUncheck)
        { 
            foreach(TreeNode node in nodes)
            {
                if (node.Checked)
                {
                    if (justUncheck)
                    {
                        node.Checked = false;
                    }
                    else
                    {
                        MLTreeTag treeTag = node.Tag as MLTreeTag;
                        if (treeTag != null)
                        {
                            if (treeTag.ObjInstance is MethodInfo)
                            {
                                TreeNode methodObjectNode = node.Parent.Parent;
                                MLTreeTag methodObjectTag = methodObjectNode.Tag as MLTreeTag;

                                MLMethodParameter methodParam = new MLMethodParameter(methodObjectTag.ObjInstance, treeTag.ObjInstance as MethodInfo);
                                AddCheckedObject(checkObjects, node.Text, methodParam);
                            }
                            else
                            {
                                AddCheckedObject(checkObjects, node.Text, treeTag.ObjInstance);
                            }
                        }
                    }
                }
                ScanForCheckedObjects(node.Nodes, checkObjects, justUncheck);
            }
        }

        /// <summary>
        /// Add checked objects
        /// </summary>
        /// <param name="checkObjects">Checked objects collection</param>
        /// <param name="key">Name of object</param>
        /// <param name="value">Object to add</param>
        void AddCheckedObject(Dictionary<string, object> checkObjects, string key, object value)
        {
            string unqueKey = key;
            int keySuffix = 0;
            while (checkObjects.ContainsKey(unqueKey))
            {
                unqueKey = string.Format("{0}{1}", key, ++keySuffix);
            }

            checkObjects.Add(unqueKey, value);
        }

        /// <summary>
        /// The end of expanding tree in sync mode
        /// </summary>
        /// <param name="node">the expanded node</param>
        private void WorkExpandEnd(TreeNode node)
        {
            node.Nodes.Clear();

            if (treeNodeCollection == null)
                return;

            foreach (MLNodeInfo nodeInfo in treeNodeCollection)
            {
                nodeInfo.ParentNode.Add(nodeInfo.Node);
            }

            treeNodeCollection.Clear();
        }

        /// <summary>
        /// Create root in sync mode
        /// </summary>
        private void StartRootSync()
        {
            if (browsedObjects != null)
            {
                foreach (object o in browsedObjects)
                {
                    if (o != null)
                    {
                        TreeNode node = MLObjectTreeExpand.GetRootNode(o);
                        objectTree.Nodes.Add(node);
                        node.Nodes.Add("Loading...");

                        //Work around to fix .Net 2.0 bug
                        if (node.NodeFont == null || node.NodeFont.Bold)
                            node.Text += String.Empty;
                    }
                }
            }
        }

        /// <summary>
        /// Gets property grids
        /// </summary>
        /// <param name="treeTag">Selected tree tag</param>
        private void GetPropertyGrid(MLTreeTag treeTag)
        {
            GetDeclaredType(treeTag);

            if (treeTag == null || treeTag.ObjInstance == null)
            {
                generalPropsGrid.SelectedObject = null;
                typeInfoPropsGrid.SelectedObject = null;
                tabTypeInfo.Text = "<Null reference>";
                objectStringValue.Text = "<Null reference>";
                return;
            }

            object tagObject = treeTag.ObjInstance;

            GetProperties(tagObject);

            //Get type information to prp grid
            typeInfoPropsGrid.SelectedObject = tagObject.GetType();
            tabTypeInfo.Text = MLUtils.GetTypeOutput(tagObject.GetType());

            //Fill object string value box
            objectStringValue.Text = tagObject.ToString();

            //If this object is audit mask then add it to discription as audit mask
            if (tagObject is SPAuditMaskType)
            {
                GetSPAuditMask(tagObject);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tagObject">Tag object</param>
        private void GetSPAuditMask(object tagObject)
        {
            SPAuditMaskType auditMask = (SPAuditMaskType)tagObject;
            StringBuilder strMask = new StringBuilder();

            if (auditMask != SPAuditMaskType.All)
            {
                foreach (SPAuditMaskType auditMaskItem in Enum.GetValues(typeof(SPAuditMaskType)))
                {
                    if ((auditMask & auditMaskItem) != SPAuditMaskType.None)
                    {
                        strMask.AppendFormat("\r\n{0}({1})", auditMaskItem.ToString(), ((int)auditMaskItem).ToString());
                        auditMask &= ~auditMaskItem;
                    }
                }

                if (auditMask != SPAuditMaskType.None)
                {
                    strMask.AppendFormat("\r\n{0}({1})", auditMask.ToString(), ((int)auditMask).ToString());
                }
            }
            else
            {
                strMask.AppendFormat("\r\n{0}({1})", auditMask.ToString(), ((int)auditMask).ToString());
            }

            objectStringValue.Text += strMask.ToString();
        }

        /// <summary>
        /// Get general property grid
        /// </summary>
        /// <param name="tagObject">Tag object</param>
        private void GetProperties(object tagObject)
        {
            int objPropsCount = 0;

            PropertyInfo[] propsInfo = tagObject.GetType().GetProperties();
            objPropsCount = propsInfo.GetLength(0);

            if (tagObject is string || objPropsCount == 0)
            {
                generalPropsGrid.SelectedObject = new MLStringProperty(tagObject.ToString());
            }
            else
            {
                generalPropsGrid.SelectedObject = tagObject;
            }
        }

        /// <summary>
        /// Get declared type property grid
        /// </summary>
        /// <param name="treeTag">Selected tree tag</param>
        private void GetDeclaredType(MLTreeTag treeTag)
        {
            if (treeTag != null)
            {
                tabDeclaredType.Text = MLUtils.GetTypeOutput(treeTag.ObjectDeclaringType);
                declaredTypePropsGrid.SelectedObject = treeTag.ObjectDeclaringType;
            }
            else
            {
                tabDeclaredType.Text = "<Null reference>";
                declaredTypePropsGrid.SelectedObject = null;
            }
        }

        #endregion 
    }
}